package com.home.school.config.aspect;

import com.home.school.service.TLogService;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * 切片保存所有非GET请求的所有请求数据到日志数据库中
 *
 * @author Lin
 * 2019/10/28 0028
 */
@Aspect
@Component
public class WebLogAspect {
    private static final List<String> HTTP_METHODS = new ArrayList<>();

    private static final String HEADER_X_FORWARDED_FOR = "x-forwarded-for";

    private static final String HEADER_X_REAL = "x-real";

    private static final String LOG_CATEGORY_API_WEB = "APP_CONTROLLER_WEB_LOG";

    private static final String LOG_CATEGORY_OPEN_WEB = "APP_CONTROLLER_OPEN_WEB_LOG";

    static {
        HTTP_METHODS.add("POST");
        HTTP_METHODS.add("PUT");
        HTTP_METHODS.add("DELETE");
        HTTP_METHODS.add("PATCH");
    }

    @Autowired
    private ObjectMapper objectMapper;

    @Autowired
    private TLogService tLogService;

    @Autowired
    private ThreadPoolTaskExecutor taskExecutor;

    @Pointcut("execution(public * com.home.school.controller..*.*(..))")
    public void apiWebLog() {
    }

    @AfterReturning("apiWebLog()")
    public void doAfterApiProcessed(JoinPoint joinPoint) {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        saveWebLog(joinPoint, attributes, 11,11, LOG_CATEGORY_API_WEB);
    }

    private void saveWebLog(JoinPoint joinPoint, ServletRequestAttributes attributes,
                            Integer userId, Integer eventId, String category) {
        if (Objects.nonNull(attributes)) {
            HttpServletRequest request = attributes.getRequest();
            String method = request.getMethod().toUpperCase();
            if (HTTP_METHODS.contains(method)) {
                String message = getMessage(request);
                String args = getArgs(joinPoint.getArgs());
                String eventName = joinPoint.getSignature().getDeclaringTypeName() + '.' + joinPoint.getSignature().getName();
                tLogService.saveLog(category, userId, eventId, eventName, args, message);
            }
        }
    }

    private String getRealIp(HttpServletRequest request) {
        if (!StringUtils.isEmpty(request.getHeader(HEADER_X_REAL))) {
            return request.getHeader(HEADER_X_REAL);
        }

        if (!StringUtils.isEmpty(request.getHeader(HEADER_X_FORWARDED_FOR))) {
            return request.getHeader(HEADER_X_FORWARDED_FOR);
        }

        return request.getRemoteAddr();
    }

    private String getArgs(Object[] args) {
        String argsStr = "";

        try {
            argsStr = objectMapper.writeValueAsString(args);
        } catch (JsonProcessingException e) {
            // ignored
        }

        return argsStr;
    }

    private String getMessage(HttpServletRequest request) {
        StringBuilder sb = new StringBuilder();

        sb.append(getRealIp(request)).append(" ");

        sb.append(request.getMethod()).append(" ").append(request.getRequestURI());

        if (!StringUtils.isEmpty(request.getQueryString())) {
            sb.append("?").append(request.getQueryString());
        }

        return sb.toString();
    }
}
